from logging import getLogger

from django import http
import json
from decimal import Decimal

from django.db import transaction
from django.shortcuts import render

# Create your views here.
from django.utils import timezone
from django.views import View
from django_redis import get_redis_connection

from goods.models import SKU
from meiduo.utils.mei_duo import LoginRequiredMixin
from order.models import OrderInfo, OrderGoods
from users.models import Address

logger = getLogger('django')


class OrderManager(LoginRequiredMixin, View):
    """
    订单管理
    """

    def get(self, request):
        """
        结算页面
        :param request: /order/
        :return: place_order.html
        """
        # 收货地址
        user = request.user
        addrs = user.address.filter(is_delete=False)

        # 订单
        redis_conn = get_redis_connection('cart')
        cart = redis_conn.hgetall('cart_%s' % user.id)
        selected = redis_conn.smembers('selected_%s' % user.id)

        skus_dict = {}
        for id in selected:
            if cart.get(id):
                skus_dict[int(id)] = int(cart.get(id))

        skus = SKU.objects.filter(id__in=skus_dict.keys())
        # 计算数量和价格
        total_count = 0
        total_amount = Decimal(0.00)
        for sku in skus:
            sku.count = skus_dict[sku.id]
            sku.amount = sku.count * sku.price
            total_count += sku.count
            total_amount += sku.amount

        freight = Decimal(10.0)

        data = {
            "user": user,
            "addrs": addrs,
            "skus": skus,
            "total_amount": total_amount,
            "total_count": total_count,
            "freight": freight,
            "payment_amount": total_amount + freight,
        }
        return render(request, 'place_order.html', data)

    def post(self, request):
        """
        提交订单
        :param request: post /order/commit/ json {'address_id':int, 'pay_method': int}
        :return: json {'order_id': order.id}
        """
        # 接收数据
        data = json.loads(request.body.decode())
        print(data)
        address_id = data.get('address_id')
        pay_method = data.get('pay_method')
        print(address_id, pay_method)
        # 验证数据
        if not all([address_id, pay_method]):
            return http.JsonResponse({'code': 4040, 'errmsg': '缺少必要参数'})

        if pay_method not in OrderInfo.PAY_METHODS_ENUM.values():
            return http.JsonResponse({'code': 4041, 'errmsg': '无效的支付方式'})

        try:
            addr = Address.objects.get(id=address_id)
        except Exception as e:
            return http.JsonResponse({'code': 4042, 'errmsg': '无效的地址'})

        # 创建订单
        user = request.user
        if not user or not user.is_authenticated:
            return http.JsonResponse({'code': 4101, 'errmsg': '请先登录'})
        # 先用字典存储，最后统一写入数据库
        order_id = timezone.localtime().strftime(
            '%Y%m%d%H%M%S') + '%09d' % user.id
        order_info = {
            'order_id': order_id,
            'user': user,
            'address': addr,
            'pay_method': pay_method,
            'freight': Decimal(10.00),
            'total_count': 0,
            'total_amount': Decimal(0.00),
            'status': OrderInfo.ORDER_STATUS_ENUM['UNPAID']
            if pay_method == OrderInfo.PAY_METHODS_ENUM['ALIPAY']
            else OrderInfo.ORDER_STATUS_ENUM['UNSEND'],
        }

        # 创建每样商品订购信息
        redis_conn = get_redis_connection('cart')
        cart = redis_conn.hgetall('cart_%s' % user.id)
        selected = redis_conn.smembers('selected_%s' % user.id)

        sku_count = {}
        for id in selected:
            if cart.get(id):
                sku_count[int(id)] = int(cart.get(id))

        skus = SKU.objects.filter(id__in=sku_count.keys())
        for sku in skus:
            sku.count = sku_count[sku.id]
            if sku.stock < sku.count:
                return http.JsonResponse(
                    {'code': 4100, 'errmsg': '%s库存不足' % sku.name})

            order_info['total_count'] += sku.count
            order_info['total_amount'] += sku.count * sku.price

        order_info['total_amount'] += order_info['freight']

        # 将保存到数据库作为一项事务
        with transaction.atomic():
            # 创建事务保存点
            save_id = transaction.savepoint()
            try:
                # 操作sql数据库
                order = OrderInfo.objects.create(**order_info)

                for sku in skus:
                    while True:
                        stock = sku.stock - sku.count
                        if stock < 0:
                            return http.JsonResponse({'code': 4100,
                                                      'errmsg': '商品已售罄:%s' % sku.name})
                        sales = sku.sales + sku.count
                        if SKU.objects.filter(id=sku.id, stock=sku.stock).update(sales=sales, stock=stock):
                            break
                        else:
                            try:
                                sku = SKU.objects.get(id=sku.id, is_launched=True)
                                sku.count = sku_count[sku.id]
                            except Exception as e:
                                return http.JsonResponse({'code': 4100,
                                                          'errmsg': '未找到商品:%s' % sku.name})

                        sku.spu.sales += sku.count
                        sku.spu.save()

                    OrderGoods.objects.create(order=order, sku=sku,
                                              count=sku.count, price=sku.price)
                # 删除redis购物车数据
                pl = redis_conn.pipeline()
                pl.hdel('cart_%s' % user.id, *selected)
                pl.srem('selected_%s' % user.id, *selected)
                pl.execute()

            except Exception as e:
                logger.error(e)
                transaction.savepoint_rollback(save_id)
                return http.JsonResponse({'code': 4011, 'errmsg': '下单失败'})

            # 提交订单成功，显式的提交一次事务
            transaction.savepoint_commit(save_id)

        return http.JsonResponse(
            {'code': 0, 'errmsg': '提交成功', 'order_id': order_id})


class OrderSuccess(View):

    def get(self, request):
        """
        订单提交成功页面
        :param request: GET /order/success/ order_id, payment_amount, pay_method
        :return: order_success.html
        """

        order_id = request.GET.get('order_id')
        payment_amount = request.GET.get('payment_amount')
        pay_method = request.GET.get('pay_method')
        data = {
            'order_id': order_id,
            'payment_amount': payment_amount,
            'pay_method': pay_method
        }

        return render(request, 'order_success.html', data)
